package cn.repository;

import cn.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import javax.transaction.Transactional;
import java.util.List;

public interface UserRepository extends JpaRepository<UserEntity, Integer> {

    UserEntity findByUserName(String username);

    /**
     * and (参数是对象)
     * <p>
     * 下面写法不对,直接报如下错误
     * java.lang.IllegalStateException:
     * Method public abstract cn.entity.UserEntity cn.repository.UserRepository.findByUserNameAndUserPhone(cn.entity.UserEntity)
     * expects at least 2 arguments but only found 1. This leaves an operator of type SIMPLE_PROPERTY for property userPhone unbound.
     * <p>
     * 就是 findByUserNameAndUserPhone() 方法需要2个参数,但只发现1个
     * <p>
     * ☆待解决：参数是对象怎么办?! ==> 若是一个类几十个属性,根据七八个条件查询,这时函数名就很长了 findByXXX,难不成形参还要单独写七八个?!
     */
//    UserEntity findByUserNameAndUserPhone(@Param("user") UserEntity user);

    // or
    UserEntity findByUserNameOrUserPhone(String userName, String userPhone);

    // is / equals
    UserEntity findByUserIdIs(Integer id);

    UserEntity findByUserIdEquals(Integer id);

    // between
    List<UserEntity> findByUserAgeBetween(Integer minAge, Integer maxAge);

    // lessThan
    List<UserEntity> findByUserAgeLessThan(Integer maxAge);

    // greaterThanEqual
    List<UserEntity> findByUserAgeGreaterThanEqual(Integer minAge);

    // after / before
    List<UserEntity> findByUserAgeAfter(Integer minAge);

    List<UserEntity> findByUserAgeBefore(Integer maxAge);

    // like / containing (like语句中的参数需要自己手写%，Containing不用再写%)
    List<UserEntity> findByUserNameLike(String name);

    List<UserEntity> findByUserNameContaining(String name);

    //  order by
    List<UserEntity> findByUserNameOrderByUserAgeDesc(String username);

    List<UserEntity> findByOrderByUserAgeDesc();

    //  in
    List<UserEntity> findByUserIdIn(List<Integer> ids);

    //  false (查找未激活用户)
    List<UserEntity> findByUserActiveFalse();

    //  ignoreCase (忽略大小写)
    List<UserEntity> findByUserNameIgnoreCase(String username);

    /*-------------------------------- 使用JPQL实现基本的增删改查 --------------------------------*/

    /**
     * nativeQuery = true时使用SQL语言，否则使用JPQL(默认nativeQuery = false)
     * 且JPQL不支持insert操作，因此要使用 nativeQuery=true 使用原生SQL进行插入操作
     * <p>
     * 增删改要用@Modifying和@Transactional注解
     * 因为@Modifying只是声明了这是一个改动操作(包含增删改)，但没有修改这个方法的事务等级，
     * 故还需@Transactional注解，该注解本质上是声明了@Transactional(readOnly=false)
     * 因此一般情况下,@Modifying和@Transactional配套使用
     * <p>
     * 参数
     * 普通参数：
     * 法1：使用 ?x ，x代表下标从1开始，参数有序，x的序号与形参对应
     * 法2：使用 id=:id 和 @Param("id")注解，参数无序，因为有@Param注解确定
     * 对象参数：
     * 如 Integer addUser(@Param("user") UserEntity user);
     * 使用时为 :#{#user.userName}、:#{#user.userAge}等
     */

    // 增
    @Modifying
    @Transactional
    @Query(value = "insert into t_user(name,age,address,phone,active) values(?1,?2,?3,?4,?5)", nativeQuery = true)
    Integer addUser(String name, Integer age, String address, String phone, Boolean active);

    @Modifying
    @Transactional
    @Query(value = "insert into t_user(name,age,address,phone,active) " +
            "values(:#{#user.userName}, :#{#user.userAge}, :#{#user.userAddress}, " +
            ":#{#user.userPhone}, :#{#user.userActive})", nativeQuery = true)
    Integer addUser(@Param("user") UserEntity user);

    // 删
    @Modifying
    @Transactional
    @Query("delete from UserEntity where id=:id")
    Integer deleteUser(@Param("id") Integer id);

    // 改
    @Modifying
    @Transactional
    @Query("update UserEntity set userPhone=?2 where userId=?1")
    Integer updatePhone(Integer id, String newPhone);

    /**
     * 查
     * <p>
     * 使用JPQL语法，不能写"select * "，要用别名。
     * 把UserEntity实体类取别名为u，再"select u"，等价于SQL中的"select *"
     */
    @Query("from UserEntity where id=?1")
    UserEntity findOneUser(Integer id);


    @Query("select u from UserEntity u where name=:#{#user.userName} and phone=:#{#user.userPhone}")
    UserEntity findOneUser(@Param("user") UserEntity user);

    @Query("from UserEntity")
    List<UserEntity> findAllUser();
}
